#
# This file is a part of the open-eBackup project.
# This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
# If a copy of the MPL was not distributed with this file, You can obtain one at
# http://mozilla.org/MPL/2.0/.
#
# Copyright (c) [2024] Huawei Technologies Co.,Ltd.
#
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
#

from typing import List

from oracle import logger
from oracle.common.device_manager.constants import StorageType, ReturnCode
from oracle.common.device_manager.device_info import DeviceInfo, LunInfo, \
    ProtectGroupInfo, SnapshotConsistencyGroup, StoragePoolInfo
from oracle.common.device_manager.device_manager import DeviceManager
from oracle.common.device_manager.storage_common import StorageCommon


class StorageV6Manager(object):
    @staticmethod
    def create_lun_snapshots(resource_id, job_id, lun_infos: List, device_manager):
        logger.info(f"start create_lun_snapshots")
        snapshots = list()
        if not device_manager or not device_manager.init_success:
            return False, snapshots
        # 创建保护组
        ret, protect_group_id = StorageV6Manager.create_protect_group(resource_id, lun_infos, device_manager)
        if not ret:
            return False, snapshots
        # 创建快照一致性组
        ret, group_id = StorageV6Manager.create_snapshot_consistency_group(job_id, protect_group_id, device_manager)
        if not ret:
            return False, snapshots
        error_code, error_desc = device_manager.query_snapshots_in_consistency_group(group_id, snapshots, lun_infos)
        if error_code != ReturnCode.SUCCESS:
            return False, snapshots
        logger.info(f"success create lun snapshots")
        return True, snapshots

    @staticmethod
    def delete_lun_snapshots(snapshot_consistency_group_id, device_info: DeviceInfo):
        device_manager = DeviceManager.create_device_inst_by_ip_list(device_info, StorageType.DORADO)
        if not device_manager or not device_manager.init_success:
            return False
        error_code, error_desc = device_manager.delete_snapshot_consistency_group(snapshot_consistency_group_id)
        if error_code == ReturnCode.SUCCESS:
            return True
        return False

    @staticmethod
    def create_protect_group(resource_id, lun_infos: List, device_manager: StorageCommon):
        logger.info(f'create protect group, resource id: {resource_id}')
        lun_ids = []
        for lun_info in lun_infos:
            lun_ids.append(lun_info.lun_id)
        if len(lun_ids) == 0:
            return False, ''
        protect_group_name = f'protect_group_{resource_id}'
        protect_group_info = ProtectGroupInfo()
        device_manager.query_protect_group(protect_group_name, protect_group_info)
        if not protect_group_info.protect_group_id:
            error_code, error_desc = device_manager.create_protect_group(
                protect_group_name, protect_group_info)
            if error_code != ReturnCode.SUCCESS:
                return False, ''
        # 判断LUN是否在保护组中，存在则不添加
        need_add_lun_ids, need_delete_lun_ids = StorageV6Manager. \
            exist_lun_in_protect_group(protect_group_info.protect_group_id, lun_ids, device_manager)
        logger.info(f"need_add_lun_ids:{need_add_lun_ids},need_delete_lun_ids:{need_delete_lun_ids}")
        if need_delete_lun_ids:
            error_code, error_desc = device_manager. \
                delete_lun_from_protect_group(need_delete_lun_ids, protect_group_info.protect_group_id)
            if error_code != ReturnCode.SUCCESS:
                return False, ''
        if need_add_lun_ids:
            error_code, error_desc = device_manager. \
                add_lun_2_protect_group_by_id(need_add_lun_ids, protect_group_info.protect_group_id)
            if error_code != ReturnCode.SUCCESS:
                return False, ''
        return True, protect_group_info.protect_group_id

    @staticmethod
    def create_snapshot_consistency_group(job_id, protect_group_id, device_manager: StorageCommon):
        logger.info(f'create snapshot consistency group, job_id: {job_id}, group id: {protect_group_id}')
        consistency_group = SnapshotConsistencyGroup()
        error_code, error_desc = device_manager.create_snapshot_consistency_group(
            job_id, protect_group_id, consistency_group)
        if error_code != ReturnCode.SUCCESS:
            return False, ''
        return True, consistency_group.group_id

    @staticmethod
    def query_lun_infos_by_wwn(lun_wwn: List, device_manager: StorageCommon):
        lun_infos = []
        for wwn in lun_wwn:
            lun_info = LunInfo()
            error_code, error_desc = device_manager.query_lun_by_wwn(wwn, lun_info)
            if error_code != ReturnCode.SUCCESS:
                logger.error(f"query_lun_infos_by_wwn failed {error_code}, {error_desc}")
                return False, []
            lun_infos.append(lun_info)
        return True, lun_infos

    @staticmethod
    def query_lun_hyper_metro_pair(device_manager: StorageCommon):
        hyper_metro_pairs = []
        error_code, error_desc = device_manager.query_all_hyper_metro_pair(hyper_metro_pairs)
        if error_code != ReturnCode.SUCCESS:
            logger.error(f"query_lun_hyper_metro_pair failed {error_code}, {error_desc}")
            return False, []
        return True, hyper_metro_pairs

    @staticmethod
    def exist_lun_in_protect_group(protect_group_id, lun_ids: List, device_manager: StorageCommon):
        lun_infos = []
        need_add_lun_ids = []
        need_delete_lun_ids = []
        error_code, error_desc = device_manager.query_lun_in_protect_group(protect_group_id, lun_infos)
        if error_code != ReturnCode.SUCCESS:
            return need_add_lun_ids, need_delete_lun_ids
        group_lun_ids = [lun_info.lun_id for lun_info in lun_infos]
        need_add_lun_ids = list(set(lun_ids).difference(set(group_lun_ids)))
        need_delete_lun_ids = list(set(group_lun_ids).difference((set(lun_ids))))
        return need_add_lun_ids, need_delete_lun_ids

    @staticmethod
    def delete_protect_group(protect_group_id, consistency_groups: List, device_manager: StorageCommon):
        # 存在快照组，先删快照组
        snaps = device_manager.query_snapshot_consistency_groups_by_protect_group_id(
            protect_group_id, consistency_groups)
        for snap in snaps:
            error_code, error_desc = device_manager.delete_snapshot_consistency_group(snap.group_id)
            if error_code != ReturnCode.SUCCESS:
                logger.error(f"delete snapshot failed, id: {snap.group_id}")
        # 删除保护组
        device_manager.delete_protect_group(protect_group_id)

    @staticmethod
    def query_storage_pool_capacity_usage_ratio(storage_pool_id, device_manager: StorageCommon):
        storage_pool_info = StoragePoolInfo()
        error_code, error_desc = device_manager.query_storage_pool_info(storage_pool_id, storage_pool_info)
        if error_code != ReturnCode.SUCCESS \
                or not storage_pool_info.storage_pool_capacity_usage_ratio:
            logger.error("cannot find storage pool capacity")
            return 0, ''
        usage_ratio = storage_pool_info.storage_pool_capacity_usage_ratio
        name = storage_pool_info.name
        logger.info(f"storage_pool_capacity_usage_ratio:{usage_ratio}")
        return usage_ratio, name
